package io.github.aaron.commonadmin.plugin;
import io.github.aaron.commonadmin.domain.SourceCompilationUnit;
import io.github.aaron.commonadmin.manager.FreemarkerTemplateManager;
import org.apache.commons.lang3.StringUtils;
import org.mybatis.generator.api.GeneratedJavaFile;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.PluginAdapter;
import org.mybatis.generator.api.dom.java.*;
import org.mybatis.generator.config.JavaClientGeneratorConfiguration;
import java.nio.charset.StandardCharsets;
import java.text.MessageFormat;
import java.util.*;

/**
 * @Author aaron01.fan
 * @Date 2025/8/28 15:33
 * @Description service类生成插件
 **/
public class ServiceGenPlugin extends PluginAdapter {

    /**
     * 记录mybatis生成的模型
     */
    private final ThreadLocal<TopLevelClass> modelBaseRecordClass = new ThreadLocal<>();


    @Override
    public boolean validate(List<String> warnings) {
        return true;
    }

    @Override
    public boolean modelBaseRecordClassGenerated(TopLevelClass topLevelClass,
                                                 IntrospectedTable introspectedTable) {
        // 添加到上下文
        modelBaseRecordClass.set(topLevelClass);
        return true;
    }

    @Override
    public List<GeneratedJavaFile> contextGenerateAdditionalJavaFiles(IntrospectedTable introspectedTable) {
        List<GeneratedJavaFile> generatedJavaFiles = new ArrayList<>();
        // 构造业务模型
        GeneratedJavaFile modelJavaFile = buildModelJavaFile();
        generatedJavaFiles.add(modelJavaFile);
        FullyQualifiedJavaType modelFullyType = modelJavaFile.getCompilationUnit().getType();
        // 构造service
        GeneratedJavaFile serviceJavaFile = buildServiceJavaFile(introspectedTable,modelFullyType);
        generatedJavaFiles.add(serviceJavaFile);
        return generatedJavaFiles;
    }

    private GeneratedJavaFile buildServiceJavaFile(IntrospectedTable introspectedTable,FullyQualifiedJavaType modelFullyType) {
        JavaClientGeneratorConfiguration javaClientGeneratorConfiguration = context.getJavaClientGeneratorConfiguration();

        // 1.准备参数
        String domainClassName = introspectedTable.getFullyQualifiedTable().getDomainObjectName();
        String servicePkg = getServicePkg(javaClientGeneratorConfiguration);
        String serviceClassName = domainClassName + "Service";
        String exampleClassName = StringUtils.substringAfterLast(introspectedTable.getExampleType(),".");
        String mapperClassName = StringUtils.substringAfterLast(introspectedTable.getMyBatis3JavaMapperType(),".");
        // 全类名
        String fullTypeSpecification = StringUtils.joinWith(".",servicePkg,serviceClassName);
        // 准备freemarker数据源
        Map<String, Object> params = new HashMap<>();
        params.put("packageName", servicePkg);
        params.put("domainClassName", modelFullyType.getShortName());
        params.put("domainFullyType", modelFullyType.getFullyQualifiedName());
        params.put("mapperClassName", mapperClassName);
        params.put("mapperFullyType", introspectedTable.getMyBatis3JavaMapperType());
        params.put("exampleClassName", exampleClassName);
        params.put("exampleFullyType", introspectedTable.getExampleType());
        params.put("serviceClassName", serviceClassName);
        params.put("beanMapperFullyType", "io.github.aaron.commonadmin.base.beanmap.BeanMapper");

        try {
            // 2.渲染模板
            String source = FreemarkerTemplateManager.getInstance()
                    .process("service-mapper.ftl", params);
            // 3.包装对象
            return new GeneratedJavaFile(new SourceCompilationUnit(source,fullTypeSpecification)
                    , javaClientGeneratorConfiguration.getTargetProject(), StandardCharsets.UTF_8.name(), context.getJavaFormatter());
        } catch (Exception e) {
            throw new RuntimeException("ServiceGeneratePlugin 生成service操作失败", e);
        }
    }

    private GeneratedJavaFile buildModelJavaFile() {
        TopLevelClass modelBaseClass = modelBaseRecordClass.get();
        String entityFullyType = modelBaseClass.getType().getFullyQualifiedName();
        String modelFullyType = entityFullyType.replace(".entity",".model") + "Model";
        TopLevelClass modelClass = new TopLevelClass(modelFullyType);
        modelClass.setVisibility(JavaVisibility.PUBLIC);
        modelClass.addImportedTypes(modelBaseClass.getImportedTypes());
        modelBaseClass.getFields().forEach(modelClass::addField);
        modelBaseClass.getMethods().forEach(modelClass::addMethod);

        // 添加属性拷贝方法
        appMapMethod(modelBaseClass, modelClass);
        appMapMethod(modelClass,modelBaseClass);
        return new GeneratedJavaFile(modelClass
                , context.getJavaModelGeneratorConfiguration().getTargetProject(), StandardCharsets.UTF_8.name(), context.getJavaFormatter());
    }

    private void appMapMethod(TopLevelClass targetClass, TopLevelClass sourceClass) {
        List<String> bodyLineList = new ArrayList<>();
        String shortName = targetClass.getType().getShortName();
        Method mapMethod = new Method("map");
        // 填充代码行
        String newLine = MessageFormat.format("{0} map = new {1}();", shortName, shortName);
        bodyLineList.add(newLine);
        for (Field field : targetClass.getFields()) {
            String setLine = MessageFormat.format("map.set{0}(this.{1});", StringUtils.capitalize(field.getName()), field.getName());
            bodyLineList.add(setLine);
        }
        String returnLine = "return map;";
        bodyLineList.add(returnLine);
        mapMethod.addBodyLines(bodyLineList);
        // 添加返回类型
        mapMethod.setReturnType(targetClass.getType());
        // 添加方法可见级别
        mapMethod.setVisibility(JavaVisibility.PUBLIC);

        Interface overrideInterface = new Interface("java.lang.Override");
        Interface beanMappingInterface = new Interface("io.github.aaron.commonadmin.base.beanmap.BeanMapping");
        // 添加泛型
        beanMappingInterface.getType().addTypeArgument(targetClass.getType());
        // 添加继承注解
        mapMethod.addAnnotation("@" + overrideInterface.getType().getShortName());
        sourceClass.addMethod(mapMethod);

        sourceClass.addImportedType(targetClass.getType());
        sourceClass.addImportedType(beanMappingInterface.getType());
        sourceClass.addImportedType(overrideInterface.getType());
        // 添加实现接口
        sourceClass.addSuperInterface(beanMappingInterface.getType());

    }

    private static String getServicePkg(JavaClientGeneratorConfiguration javaClientGeneratorConfiguration) {
        String servicePkg = javaClientGeneratorConfiguration.getProperty("serviceTargetPackage");
        if (StringUtils.isBlank(servicePkg)){
            String basePackage = javaClientGeneratorConfiguration.getTargetPackage();
            servicePkg = basePackage.replace(".repository",".service");
        }
        return servicePkg;
    }

}
